// fileName      :  funcs.go
// createdAt     :  2021-12-16
// description   :

package utils

import (
	"bytes"
	"crypto/md5"
	"database/sql"
	"encoding/hex"
	"encoding/json"
	"fmt"
	"math"
	"math/rand"
	"net/url"
	"reflect"
	"strconv"
	"strings"
	"time"
)

// 获取随机字符串
//    length：字符串长度
func GetRandomString(length int) string {
	str := "0123456789AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz"
	var (
		result []byte
		b      []byte
		r      *rand.Rand
	)
	b = []byte(str)
	r = rand.New(rand.NewSource(time.Now().UnixNano()))
	for i := 0; i < length; i++ {
		result = append(result, b[r.Intn(len(b))])
	}
	return string(result)
}

// 字符串转Float64
func String2Float64(floatStr string) (floatNum float64) {
	floatNum, _ = strconv.ParseFloat(floatStr, 64)
	return
}

// 字符串转Float32
func String2Float32(floatStr string) (floatNum float32) {
	float, _ := strconv.ParseFloat(floatStr, 32)
	floatNum = float32(float)
	return
}

// Float64转字符串
//    floatNum：float64数字
//    prec：精度位数（不传则默认float数字精度）
func Float64ToString(floatNum float64, prec ...int) (floatStr string) {
	if len(prec) > 0 {
		floatStr = strconv.FormatFloat(floatNum, 'f', prec[0], 64)
		return
	}
	floatStr = strconv.FormatFloat(floatNum, 'f', -1, 64)
	return
}

// Float32转字符串
//    floatNum：float32数字
//    prec：精度位数（不传则默认float数字精度）
func Float32ToString(floatNum float32, prec ...int) (floatStr string) {
	if len(prec) > 0 {
		floatStr = strconv.FormatFloat(float64(floatNum), 'f', prec[0], 32)
		return
	}
	floatStr = strconv.FormatFloat(float64(floatNum), 'f', -1, 32)
	return
}

// 字符串转Int
func String2Int(intStr string) (intNum int) {
	intNum, _ = strconv.Atoi(intStr)
	return
}

func Object2String(obj interface{}) string {
	if obj != nil {
		if "string" == reflect.TypeOf(obj).String() {
			return obj.(string)
		}
	}
	return ""
}

func Object2Float64(obj interface{}) float64 {
	if obj != nil {
		if "float64" == reflect.TypeOf(obj).String() {
			return obj.(float64)
		}
	}
	return 0
}

// 字符串转Int32
func String2Int32(intStr string) (int32Num int32) {
	int32Num = int32(String2Int(intStr))
	return
}

// 字符串转Int64
func String2Int64(intStr string) (int64Num int64) {
	int64Num = int64(String2Int(intStr))
	return
}

// Int转字符串
func Int2String(intNum int) (intStr string) {
	intStr = strconv.Itoa(intNum)
	return
}

// Int32转字符串
func Int322String(intNum int32) (int32Str string) {
	// 10, 代表10进制
	int32Str = strconv.FormatInt(int64(intNum), 10)
	return
}

// Int64转字符串
func Int642String(intNum int64) (int64Str string) {
	// 10, 代表10进制
	int64Str = strconv.FormatInt(intNum, 10)
	return
}

// 判断字符串
func EqualString(con bool, a string, b string) string {
	if con {
		return a
	} else {
		return b
	}
}

func QueryUnescape(str string) string {
	str, _ = url.QueryUnescape(str)
	sUnicode := strings.Split(str, "\\u")
	var context string
	for _, v := range sUnicode {
		if len(v) < 1 {
			continue
		}
		temp, err := strconv.ParseInt(v, 16, 32)
		if err != nil {
			return str
		}
		context += fmt.Sprintf("%c", temp)
	}
	return context
}

func Md5(s string) string {
	m := md5.Sum([]byte(s))
	return hex.EncodeToString(m[:])
}

// 对象转换json串
func Object2Json(data interface{}) string {
	jsons, errs := json.Marshal(data)
	if errs != nil {
		return ""
	}
	return string(jsons)
}

func Json2Object(obj interface{}, str string) error {
	return json.Unmarshal([]byte(str), &obj)
}

func MapMarshal(data interface{}, result interface{}) {
	str, err := json.Marshal(data)
	if err == nil {
		json.Unmarshal(str, result)
	}
}

func Permission2Map(preStr string) *map[string]int {
	var m map[string]int
	m = make(map[string]int)
	pres := strings.Split(preStr, ",")
	for _, per := range pres {
		s := strings.Split(per, ":")
		if len(s) == 2 {
			m[s[0]] = String2Int(s[1])
		}
	}
	return &m
}

func Map2Permission(preMap *map[string]int) string {
	var result bytes.Buffer
	for key, per := range *preMap {
		result.WriteString(fmt.Sprintf("%s:%d,", key, per))
	}
	return result.String()
}

func mergePermission(per1 *map[string]int, per2 *map[string]int) {
	for key, per := range *per2 {
		orgVal := (*per1)[key]
		if (orgVal & per) == 0 {
			(*per1)[key] = orgVal ^ per
		} else {
			(*per1)[key] = int(math.Max(float64(orgVal), float64(per)))
		}
	}
}

// 合并权限
func MergePermission(rootPermissions string, permissions ...string) string {
	if len(permissions) > 0 {
		root := Permission2Map(rootPermissions)
		for _, permission := range permissions {
			mergePermission(root, Permission2Map(permission))
		}
		return Map2Permission(root)
	}
	return ""
}

// 弥补三元运算
func Ternary(c bool, s interface{}, p interface{}) interface{} {
	if c {
		return s
	} else {
		return p
	}
}

func CurrTime() sql.NullTime {
	return sql.NullTime{Time: time.Now(), Valid: true}
}
